#pragma once
#include <memory>
#include <string>
#include <vector>
#include "symtable.hpp"


enum class StmtType { if_, ifelse, simple, while_ };

// 所有 AST 的基类
class BaseAST {
 public:
  virtual ~BaseAST() = default;
  // 输出 KoopaIR 到 stdout
  virtual void KoopaIR() const = 0;
};

/************************CompUnit*************************/

// CompUnit ::= FuncDef;
class CompUnitAST : public BaseAST {
 public:
  std::unique_ptr<std::vector<std::unique_ptr<BaseAST> > > comp_unit_item_list;
  void KoopaIR() const override;
};

class CompUnitItemAST : public BaseAST {
 public:
  int type;
  std::unique_ptr<BaseAST> decl1_funcdef2;
  void KoopaIR() const override;
};

/**************************Decl***************************/

// Decl ::= ConstDecl | VarDecl;
class DeclAST : public BaseAST {
 public:
  int type;
  std::unique_ptr<BaseAST> const_decl1_var_decl2;
  void KoopaIR() const override;
};

// ConstDecl ::= "const" BType ConstDefList ";";
// ConstDefList ::= ConstDef | ConstDefList "," ConstDef;
class ConstDeclAST : public BaseAST {
 public:
  std::string b_type;
  std::unique_ptr<std::vector<std::unique_ptr<BaseAST> > > const_def_list;
  void KoopaIR() const override;
};

// BType ::= "int";
class BTypeAST : public BaseAST {
 public:
  void KoopaIR() const override;
};

// ConstDef ::= IDENT "=" ConstInitVal;
class ConstDefAST : public BaseAST {
 public:
  std::string ident;
  std::unique_ptr<BaseAST> const_init_val;
  void KoopaIR() const override;
};

// ConstInitVal ::= ConstExp;
class ConstInitValAST : public BaseAST {
 public:
  std::unique_ptr<BaseAST> const_exp;
  void KoopaIR() const override;
  int Calc() const;
};

// VarDecl ::= BType VarDefList ";";
// VarDefList ::= VarDef | VarDefList "," VarDef;
class VarDeclAST : public BaseAST {
 public:
  std::string b_type;
  std::unique_ptr<std::vector<std::unique_ptr<BaseAST> > > var_def_list;
  void KoopaIR() const override;
};

// VarDef ::= IDENT | IDENT "=" InitVal;
class VarDefAST : public BaseAST {
 public:
  int type;
  std::string ident;
  std::unique_ptr<BaseAST> init_val;
  void KoopaIR() const override;
};

// InitVal ::= Exp;
class InitValAST : public BaseAST {
 public:
  std::unique_ptr<BaseAST> exp;
  void KoopaIR() const override;
  int Calc() const;
};

/**************************Func***************************/
// FuncDef ::= FuncType IDENT "(" FuncFParams ")" Block;
// FuncFParams ::= FuncFParam | FuncFParams "," FuncFParam;
class FuncDefAST : public BaseAST {
 public:
  std::string func_type;
  std::string ident;
  std::unique_ptr<BaseAST> block;
  std::unique_ptr<std::vector<std::unique_ptr<BaseAST> > > func_f_param_list;
  void KoopaIR() const override;
};
// FuncType ::= "void" | "int";
class FuncTypeAST : public BaseAST {
 public:
 std::string type;
  void KoopaIR() const override;
};
// FuncFParam ::= BType IDENT;
class FuncFParamAST : public BaseAST {
 public:
  std::string type;
  std::string ident;
  void KoopaIR() const override;
  void Alloc() const;
};

/**************************Block***************************/

// Block ::= "{" BlockItemList "}";
// BlockItemList ::=  | BlockItemList BlockItem;
class BlockAST : public BaseAST {
 public:
  std::unique_ptr<std::vector<std::unique_ptr<BaseAST> > > block_item_list;
  void KoopaIR() const override;
};

// BlockItem ::= Decl | Stmt;
class BlockItemAST : public BaseAST {
 public:
  int type;
  std::unique_ptr<BaseAST> decl1_stmt2;
  void KoopaIR() const override;
};

// Stmt ::= LVal "=" Exp ";"
//        | Exp ";"
//        | ";"
//        | Block
//        | "return" Exp ";";
//        | "return" ";";
class StmtAST : public BaseAST {
 public:
  int type;
  std::unique_ptr<BaseAST> lval1_block4;
  std::unique_ptr<BaseAST> exp;
  std::unique_ptr<BaseAST> if_stmt;
  std::unique_ptr<BaseAST> else_stmt;
  std::unique_ptr<BaseAST> while_stmt;
  void KoopaIR() const override;
  void store_to_lval() const;
  void print(int level) const;
};
// if 语句类型 AST 节点
class IfStmtAST : public StmtAST {
public:
  std::unique_ptr<BaseAST> exp; // if 语句的条件表达式
  std::unique_ptr<BaseAST> if_stmt;      // if 语句的主体
  std::unique_ptr<BaseAST> else_stmt; // else 语句的主体，若存在
  std::unique_ptr<BaseAST> while_stmt;
  void KoopaIR() const override;
};

class StmtWhileAST : public BaseAST {
 public:
  std::unique_ptr<BaseAST> exp;
  std::unique_ptr<BaseAST> while_stmt;
  void KoopaIR() const override;
};
class BCStmtAST : public StmtAST {
public:
  std::unique_ptr<BaseAST> exp; // if 语句的条件表达式
  std::unique_ptr<BaseAST> while_stmt;
  void KoopaIR() const override;
};

/***************************Exp***************************/

class ExpBaseAST : public BaseAST {
 public:
  virtual void KoopaIR() const = 0;  // 生成Koopa中间代码
    virtual int Calc() const = 0;      // 计算表达式的值
    virtual ~ExpBaseAST() = default;   // 虚析构函数
};

// Exp ::= LOrExp;
class ExpAST : public ExpBaseAST {
 public:
  std::unique_ptr<BaseAST> lorexp;
  void KoopaIR() const override;
  int Calc() const override;
};

// LVal ::= IDENT;
class LValAST : public ExpBaseAST {
public:
    std::string ident;  // 标识符
    void KoopaIR() const override;
    int Calc() const override;
};

class PrimaryExpAST : public ExpBaseAST {
public:
    int type; // 1 = LVal, 2 = Exp, 3 = Number
    std::shared_ptr<BaseAST> exp1_lval2;
    int number;
    void KoopaIR() const override;
    int Calc() const override;
};
//u
class UnaryExpAST : public ExpBaseAST {
public:
    int type; 
    char unaryop; // "+", "-", "!"
    std::shared_ptr<BaseAST> primaryexp1_unaryexp2;
    void KoopaIR() const override;
    int Calc() const override;
    std::string ident;
    std::unique_ptr<std::vector<std::unique_ptr<BaseAST> > > func_r_param_list;
};

class MulExpAST : public ExpBaseAST {
public:
    int type; // 1 = UnaryExp, 2 = MulExp MulOp UnaryExp
    char mulop; // "*", "/", "%"
    std::shared_ptr<BaseAST> mulexp, unaryexp;
    void KoopaIR() const override;
    int Calc() const override;
};

class AddExpAST : public ExpBaseAST {
public:
    int type; // 1 = MulExp, 2 = AddExp AddOp MulExp
    char addop; // "+", "-"
    std::shared_ptr<BaseAST> addexp, mulexp;
    void KoopaIR() const override;
    int Calc() const override;
};

class RelExpAST : public ExpBaseAST {
public:
    int type; // 1 = AddExp, 2 = RelExp RelOp AddExp
    std::string relop; // "<", ">", "<=", ">="
    std::shared_ptr<BaseAST> relexp, addexp;
    void KoopaIR() const override;
    int Calc() const override;
};

class EqExpAST : public ExpBaseAST {
public:
    int type; // 1 = RelExp, 2 = EqExp EqOp RelExp
    std::string eqop; // "==", "!="
    std::shared_ptr<BaseAST> eqexp, relexp;
    void KoopaIR() const override;
    int Calc() const override;
};

class LAndExpAST : public ExpBaseAST {
public:
    int type; // 1 = EqExp, 2 = LAndExp "&&" EqExp
    std::shared_ptr<BaseAST> landexp, eqexp;
    void KoopaIR() const override;
    int Calc() const override;
};

class LOrExpAST : public ExpBaseAST {
public:
    int type; // 1 = LAndExp, 2 = LOrExp "||" LAndExp
    std::shared_ptr<BaseAST> lorexp, landexp;
    void KoopaIR() const override;
    int Calc() const override;
};

class ConstExpAST : public ExpBaseAST {
public:
    std::shared_ptr<BaseAST> exp;
    void KoopaIR() const override;
    int Calc() const override;
};